<?php

// @formatter:off
/**
 * @file WCCollection.php
 * @author Alejandro Dario Simi
 * @date $Date: 2014-06-03 03:40:32 +0000 (Tue, 03 Jun 2014) $
 *
 * $Id: WCCollection.php 112 2014-06-03 03:40:32Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/trunk/includes/representations/WCCollection.php $
 */
// @formatter:on

/**
 * @class WCCollection
 * This class represents entries saved in the table '%collections'.
 */
class WCCollection extends WCRepresentationGroup implements WCPreviews, WCSearchIndexable, WCCountComics, WCCountImages, WCCountCollections, WCFlowContainer, WCFlowItem {
	/**
	 * @var string Special character to use as name's separator in collction's
	 * paths.
	 */
	public static $PathSeparator = "/";
	/**
	 * @var string[] This variable holds the list of columns that cannot be
	 * directly modified by the pseudo-method __set().
	 * In this case col_id and col_group.
	 */
	protected $_PropertiesReadOnly = array(
		"id",
		"group"
	);
	/**
	 * @var string[] This variable holds the list of columns that must be
	 * treated as booleans and then send to the database as 'Y' and 'N' by
	 * the pseudo-method __set().
	 * In this case col_valid_preview and col_indexed.
	 */
	protected $_PropertiesBoolean = array(
		"indexed",
		"valid_flow",
		"valid_preview"
	);
	/**
	 * @var string This is the prefix of every column on the table
	 * '%collections'.
	 */
	protected $_PropertiesPrefix = "col_";
	/**
	 * @var string This is the name of the represented table. In this case,
	 * '%collections'.
	 */
	protected $_PropertiesTable = "collections";
	/**
	 * @var WCCollectionsHolder This is a pointer to the holder to which
	 * this collection representation is attached.
	 */
	protected $_holder = false;
	/**
	 * @var WCGContainer This container holds all comics of the collection.
	 */
	protected $_comics = false;
	/**
	 * @var WCGContainer This container holds all images of the collection.
	 */
	protected $_images = false;
	/**
	 * @var WCGContainer This container holds all sub-collections.
	 */
	protected $_collections = false;
	/**
	 * @var string[string[string]] This is the list of collections identifiers
	 * of the branch where this collection is hanging. When it's false, it
	 * means it is not yet built.
	 */
	protected $_collectionPath = false;
	/**
	 * @var string This is similar to '$_collectionPath' but its only a
	 * string. When it's false, it means it is not yet built.
	 */
	protected $_path = false;
	protected $_previews = array();
	protected $_previewsLoaded = false;
	//
	// Magic methods.
	/**
	 * Class basic constructor.
	 */
	public function __construct() {
		//
		// Calling the generic setting made by the inherited class.
		parent::__construct();
		//
		// Setting the holder pointer. It always use the collections
		// holder singleton.
		global $wcCollectionsHolder;
		$this->_holder = $wcCollectionsHolder;
	}
	//
	// Public methods.
	/**
	 * This method allows to add a sub-collection.
	 *
	 * @param WCCollection $collection Collection to be added.
	 * @return boolean Returns true if the sub-collection was successfully
	 * added.
	 */
	public function addCollection(WCCollection &$collection) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking if the current collection and the one to be added
		// have no issues.
		if($this->ok() && $collection->ok()) {
			//
			// Increasing the children count on the current
			// collection.
			$this->subcount++;
			//
			// Setting this collection as parent for the one being
			// added.
			$collection->parent = $this->id;
			//
			// Because a new collection is been added, current
			// previews are no longer valid and they must be
			// regenerated when possible.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Adding collection to the list of sub-collections.
			$this->_collections->addId($collection->id());
			//
			// At this point, addition is considered as a success.
			$out = true;
		}
		//
		// Return the addition results.
		return $out;
	}
	/**
	 * This method allows to add a comic to the represented collection.
	 *
	 * @param WCComic $comic Comic to be added.
	 * @return boolean Returns true if the sub-collection was successfully
	 * added.
	 */
	public function addComic(WCComic &$comic) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking if the current collection and the one to be added
		// have no issues.
		if($this->ok() && $comic->ok()) {
			//
			// Increasing the children count on the current
			// collection.
			$this->count++;
			//
			// Setting this collection as parent for the comic being
			// added.
			$comic->collection = $this->id;
			//
			// Because a new comic is been added, current
			// previews are no longer valid and they must be
			// regenerated when possible.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Adding comic to the list of comics.
			$this->_comics->addId($comic->id());
			//
			// At this point, addition is considered as a success.
			$out = true;
		}
		//
		// Return the addition results.
		return $out;
	}
	/**
	 * This method allows to add a image to the represented collection.
	 *
	 * @param WCImage $image Image to be added.
	 * @return boolean Returns true if the sub-collection was successfully
	 * added.
	 */
	public function addImage(WCImage &$image) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking if the current collection and the one to be added
		// have no issues.
		if($this->ok() && $image->ok()) {
			//
			// Increasing the children count on the current
			// collection.
			$this->icount++;
			//
			// Setting this collection as parent for the image being
			// added.
			$image->collection = $this->id;
			//
			// Because a new image is been added, current
			// previews are no longer valid and they must be
			// regenerated when possible.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Adding image to the list of images.
			$this->_images->addId($image->id());
			//
			// At this point, addition is considered as a success.
			$out = true;
		}
		//
		// Return the addition results.
		return $out;
	}
	/**
	 * This recursive method creates a list of collections' descriptors
	 * representing a branch in the collections tree.
	 * Such lists is ordered from the top collection to the current one and
	 * each element contains name and id of each collection in the list.
	 *
	 * @return array Returns the list of collections on the branch from top
	 * to the current collection. If there's any issue, it returns false.
	 */
	public function collectionPath() {
		//
		// Checking if the path is not already built.
		if($this->_collectionPath === false) {
			//
			// Checking if current collection has no issues.
			if($this->ok()) {
				//
				// Creating the element to represent this
				// collection.
				$this->_collectionPath = array(array(
						"id" => $this->id,
						"name" => $this->name
				));
				//
				// Checking if this is a top collection.
				if($this->parent > 0) {
					//
					// Looking for the parent collection.
					$aux = $this->_holder->item($this->parent);
					//
					// Asking for its parent collection own
					// path.
					$this->_collectionPath = array_merge($aux->collectionPath(), $this->_collectionPath);
				}
			}
		}
		//
		// Returning collection's path.
		return $this->_collectionPath;
	}
	/**
	 * This method allows to get the list of sub-collections.
	 *
	 * @return WCCollection[] Returns a list of collections.
	 */
	public function collections() {
		//
		// Ensuring containers existence.
		$this->createContainers();
		//
		// Checking if the current collection has no issues and there's no
		// sub-collections list built
		if($this->ok()) {
			//
			// Preparing the statement to load all sub-collections.
			// @{
			$stmt = false;
			$stmtID = __CLASS__."::".__FUNCTION__;
			if($this->_db->has($stmtID)) {
				$stmt = $this->_db->get($stmtID);
			} else {
				$query = "select  col_id\n";
				$query .= "from    {$this->_dbprefix}collections\n";
				$query .= "where   col_group  = :group\n";
				$query .= " and    col_parent = :parent\n";

				$stmt = $this->_db->prepare($stmtID, $query);
			}
			// @}
			//
			// Asking for sub-collections.
			$params = array(
				":group" => $this->group()->id(),
				":parent" => $this->id
			);
			if($stmt->execute($params)) {
				//
				// Filling the list of sub-collections.
				foreach($stmt->fetchAll() as $row) {
					//
					// Adding a collection id to the list.
					$this->_collections->addId($row["col_id"]);
				}
			}
		}
		//
		// Returning the list of sub-collections.
		return $this->_collections->items();
	}
	/**
	 * This method is similar to 'collections()', but it returns all
	 * sub-collection until the leaves giving this way a list of all
	 * collections related to this node in the tree.
	 *
	 * @return WCCollection[] Returns a list of collections.
	 */
	public function collectionsFull() {
		//
		// Setting default value to be returned.
		$out = array();
		//
		// Getting all sub-collections and their children.
		foreach($this->collections() as $collection) {
			$out[] = $collection;
			foreach($collection->collectionsFull() as $child) {
				$out[] = $child;
			}
		}
		//
		// Returning results.
		return $out;
	}
	/**
	 * This method allows to get the list of comics having the current
	 * collection as a father.
	 *
	 * @return WCComics[] Returns a list of comics.
	 */
	public function comics() {
		//
		// Ensuring containers existence.
		$this->createContainers();
		//
		// Checking if the current collection has no issues.
		if($this->ok() && $this->_comics->count() == 0) {
			//
			// Preparing the statement to load all collection's comics.
			// @{
			$stmt = false;
			$stmtID = __CLASS__."::".__FUNCTION__;
			if($this->_db->has($stmtID)) {
				$stmt = $this->_db->get($stmtID);
			} else {
				$query = "select  cmc_id\n";
				$query .= "from    {$this->_dbprefix}comics\n";
				$query .= "where   cmc_group      = :group\n";
				$query .= " and    cmc_collection = :collection\n";
				$query .= "order by cmc_collection_order,cmc_name asc\n";

				$stmt = $this->_db->prepare($stmtID, $query);
			}
			// @}
			//
			// Asking for comics.
			$params = array(
				":group" => $this->group()->id(),
				":collection" => $this->id
			);
			if($stmt->execute($params)) {
				//
				// Filling the list of comics.
				foreach($stmt->fetchAll() as $row) {
					//
					// Adding a comic id to the list.
					$this->_comics->addId($row["cmc_id"]);
				}
			}
		}
		//
		// Returning the list of comics.
		return $this->_comics->items();
	}
	public function countCollections() {
		return $this->subcount;
	}
	public function countComics() {
		return $this->count;
	}
	public function countImages() {
		return $this->icount;
	}
	public function countItems() {
		return $this->countCollections() + $this->countComics() + $this->countImages();
	}
	public function flow() {
		return WCFlowManager::I()->flowOf($this);
	}
	public function flowItemType() {
		return WCFlow::ItemTypeCollection;
	}
	public function flowType() {
		return WCFlowManager::TypeCollectionFlow;
	}
	public function generateFlow() {
		$items = array();

		foreach($this->collectionsFull() as $item) {
			$items[] = $item;
		}
		foreach($this->comics() as $item) {
			$items[] = $item;
		}
		foreach($this->images() as $item) {
			$items[] = $item;
		}

		$this->setValidFlow(WCFlowManager::I()->registerFlow($this, $items));
	}
	/**
	 * @todo doc
	 *
	 * @return boolean Returns true if a previews list was generated.
	 */
	public function generatePreviews() {
		//
		// This is the value to return by default.
		$out = false;
		//
		// Invalidating view cache.
		WCViewManager::I()->invalidate(WCViewManager::KeyCollection, $this->id());

		if(WCPreviewsManager::I()->createCollectionPreviews($this)) {
			//
			// Collection's previews are set as valid.
			$this->setValidPreviews(true);
			//
			// At this point, it is considered that a list of
			// previews was found and set to the current
			// collection.
			$out = true;

			$this->_previewsLoaded = false;
		}
		//
		// This is a good opportunity to update item's counts.
		$this->updateStats();
		//
		// Returning generation results.
		return $out;
	}
	public function hasCollections() {
		return $this->subcount > 0;
	}
	public function hasComics() {
		return $this->count > 0;
	}
	public function hasImages() {
		return $this->icount > 0;
	}
	public function hasItems() {
		return $this->hasCollections() || $this->hasComics() || $this->hasImages();
	}
	/**
	 * This method checks if there is a preview for this collection.
	 *
	 * @return boolean Returns true when there's a preview for this
	 * collection.
	 */
	public function hasPreview() {
		//
		// It has the same result as hasPreviews().
		return $this->hasPreviews();
	}
	/**
	 * This method checks if there are previews for this collection.
	 *
	 * @return boolean Returns true when there are previews for this
	 * collection.
	 */
	public function hasPreviews() {
		$this->loadPreviews();

		return count($this->_previews) > 0;
	}
	public function hasValidFlow() {
		return $this->valid_flow;
	}
	public function hasValidPreviews() {
		return $this->valid_preview;
	}
	/**
	 * This method allows to get the list of images having the current
	 * collection as a father.
	 *
	 * @return WCImages[] Returns a list of images.
	 */
	public function images() {
		//
		// Ensuring containers existence.
		$this->createContainers();
		//
		// Checking if the current collection has no issues.
		if($this->ok() && $this->_images->count() == 0) {
			//
			// Preparing the statement to load all collection's images.
			// @{
			$stmt = false;
			$stmtID = __CLASS__."::".__FUNCTION__;
			if($this->_db->has($stmtID)) {
				$stmt = $this->_db->get($stmtID);
			} else {
				$query = "select  img_id\n";
				$query .= "from    {$this->_dbprefix}images\n";
				$query .= "where   img_group      = :group\n";
				$query .= " and    img_collection = :collection\n";
				$query .= "order by img_collection_order,img_name asc\n";

				$stmt = $this->_db->prepare($stmtID, $query);
			}
			// @}
			//
			// Asking for images.
			$params = array(
				":group" => $this->group()->id(),
				":collection" => $this->id
			);
			if($stmt->execute($params)) {
				//
				// Filling the list of images.
				foreach($stmt->fetchAll() as $row) {
					//
					// Adding a image id to the list.
					$this->_images->addId($row["img_id"]);
				}
			}
		}
		//
		// Returning the list of images.
		return $this->_images->items();
	}
	/**
	 * This method allows to know whether an item is indexed or not. Also it
	 * allows to change such status.
	 *
	 * @param boolean $value New status to be set. When absent, this method
	 * works as a getter.
	 * @return boolean Returns true when the object is indexed.
	 */
	public function indexed($value = null) {
		if(!is_null($value)) {
			$this->indexed = $value;
		}

		return $this->indexed;
	}
	/**
	 * This method allows to get the current collection parent.
	 *
	 * @return WCCollection Returns a collection when it's not at the top,
	 * otherwise, returns null.
	 */
	public function parentCollection() {
		//
		// This is the default value to be returned.
		$out = null;
		//
		// Checking if the current collection is not a top one.
		if($this->parent) {
			//
			// Loading the collection's holder.
			global $wcCollectionsHolder;
			//
			// Getting the parent collection.
			$out = $wcCollectionsHolder->item($this->parent);
			//
			// If the parent couldn't be got or it has issues, no
			// collection is returned.
			if(!$out || !$out->ok()) {
				$out = null;
			}
		}
		// Returning the parent collection.
		return $out;
	}
	/**
	 * This method is similar to 'collectionPath()' but it only returns a
	 * simple string similar to a directories path, i.e. something like:
	 * 	/parent-collection/collection
	 *
	 * @return string Returns a collection path.
	 */
	public function path() {
		//
		// Checking if the path is not already built.
		if($this->_path === false) {
			//
			// Setting a default value to be returned.
			$this->_path = "";
			//
			// Getting the current path.
			$path = $this->collectionPath();
			//
			// Checking that the current path is correct.
			if($path) {
				foreach($path as $subPath) {
					$this->_path .= self::$PathSeparator.$subPath["name"];
				}
			}
		}
		//
		// Returning collection's path.
		return $this->_path;
	}
	/**
	 * This method allows to get the thumbnail associated with the current
	 * collection.
	 *
	 * @return string Returns an image URIs.
	 */
	public function preview() {
		if($this->hasPreview()) {
			$list = $this->_previews;
			return array_shift($list);
		} else {
			global $wcDefaults;
			return $wcDefaults["preview"];
		}
	}
	/**
	 * This method allows to get the list of thumbnails associated with the
	 * current collection.
	 *
	 * @return string[] Returns a list of image URIs.
	 */
	public function previews() {
		$this->loadPreviews();

		return $this->_previews;
	}
	public function reload() {
		$this->_comics = false;
		$this->_images = false;
		$this->_collections = false;
		$this->_collectionPath = false;
		$this->_path = false;

		return parent::reload();
	}
	/**
	 * This method removes a collection from the table. Internally calls to
	 * the inherited class remove() method, but before that, it clears all
	 * dependencies.
	 *
	 * @return boolean Returns the same value than WCGTableRepresentation::remove().
	 */
	public function remove() {
		//
		// Removing it as parent from all its comics.
		foreach($this->comics() as $comic) {
			//
			// Zero means no collection.
			$comic->collection = 0;
		}
		//
		// Removing it as parent from all its sub-collections.
		//
		// @note: this means that every sub-collection will become top
		// collections.
		foreach($this->collections() as $collection) {
			//
			// Zero means no collection.
			$collection->collection = 0;
		}
		//
		// Calling to the inherited method and returning its result.
		return parent::remove();
	}
	/**
	 * This method allows to remove a sub-collection.
	 *
	 * @param WCCollection $collection Sub-collection to be removed.
	 * @return boolean Returns true when the sub-collection was successfully
	 * removed from this collection.
	 */
	public function removeCollection(WCCollection &$collection) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking that:
		//	- this collection has no issues.
		//	- the sub-collection to be removed has no issues.
		//	- and the sub-collection has this collection as parent.
		if($this->ok() && $collection->ok() && $collection->parent == $this->id) {
			//
			// Decreasing the sub-collections counter.
			$this->subcount--;
			//
			// Setting no parent to the sub-collection.
			//
			// @note: this means the sub-collection will become a top
			// one
			$collection->parent = 0;
			//
			// Setting this collection's previews as no valid.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Removing collection from the list of sub-collections.
			$this->_collections->removeId($collection->id());
			//
			// At this point, it is considered that it was removed.
			$out = true;
		}

		return $out;
	}
	/**
	 * This method allows to remove a comic from this collection.
	 *
	 * @param WCComic $comic Comic to be removed.
	 * @return boolean Returns true when the comic was successfully
	 * removed from this collection.
	 */
	public function removeComic(WCComic &$comic) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking that:
		//	- this collection has no issues.
		//	- the comic to be removed has no issues.
		//	- and the comic belongs to this collection.
		if($this->ok() && $comic->ok() && $comic->collection == $this->id) {
			//
			// Decreasing the comics counter.
			$this->count--;
			//
			// Setting no collection to the comic.
			$comic->collection = 0;
			//
			// Setting this collection's previews as no valid.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Removing comic from the list of comics.
			$this->_comics->removeId($comic->id());
			//
			// At this point, it is considered that it was removed.
			$out = true;
		}

		return $out;
	}
	/**
	 * This method allows to remove a image from this collection.
	 *
	 * @param WCImage $image Image to be removed.
	 * @return boolean Returns true when the image was successfully
	 * removed from this collection.
	 */
	public function removeImage(WCImage &$image) {
		//
		// This is the default value to be returned.
		$out = false;
		//
		// Checking that:
		//	- this collection has no issues.
		//	- the image to be removed has no issues.
		//	- and the image belongs to this collection.
		if($this->ok() && $image->ok() && $image->collection == $this->id) {
			//
			// Decreasing the images counter.
			$this->count--;
			//
			// Setting no collection to the image.
			$image->collection = 0;
			//
			// Setting this collection's previews as no valid.
			$this->setValidPreviews(false);
			//
			// Collection flow is no longer valid.
			$this->setValidFlow(false);
			//
			// Ensuring containers existence.
			$this->createContainers();
			//
			// Removing image from the list of images.
			$this->_images->removeId($image->id());
			//
			// At this point, it is considered that it was removed.
			$out = true;
		}

		return $out;
	}
	public function setValidFlow($valid = true) {
		$this->valid_flow = $valid;
	}
	public function setValidPreviews($valid = true) {
		$this->valid_preview = $valid;

		if(!$valid && $this->parentCollection()) {
			$this->parentCollection()->setValidPreviews(false);
		}
	}
	/**
	 * This method allows to get a list of phrases that must be associated with an
	 * item.
	 *
	 * @return string[] Returns a list of phrases.
	 */
	public function words() {
		$words = WCSearch::StringToPatterns($this->name());
		return $words;
	}
	//
	// Protected methods.
	/**
	 * The method creates all required containers.
	 */
	protected function createContainers() {
		//
		// Checking sub-collections container.
		if(!$this->_collections) {
			//
			// Creating a list for sub-collections.
			$this->_collections = new WCContainer(WCCollectionsHolder::I());
		}
		//
		// Checking comics container.
		if(!$this->_comics) {
			//
			// Creating a list for comics.
			$this->_comics = new WCContainer(WCComicsHolder::I());
		}
		//
		// Checking images container.
		if(!$this->_images) {
			//
			// Creating a list for images.
			$this->_images = new WCContainer(WCImagesHolder::I());
		}
	}
	protected function loadPreviews() {
		if(!$this->_previewsLoaded) {
			$this->_previews = WCPreviewsManager::I()->getPreviews($this->group(), WCPreviewsManager::TypeCollection, $this->id());

			if(count($this->_previews) <= 0) {
				$this->setValidPreviews(false);
			} else {
				global $wcPaths;
				foreach($this->_previews as $key => $value) {
					$this->_previews[$key] = WCSanitizer::WComixPath("{$wcPaths["cache-directory-uri"]}/{$wcPaths["cache-thumbs-dirname"]}/{$value}");
				}
			}

			$this->_previewsLoaded = true;
		}
	}
	/**
	 * This is an internal method called by the pseudo-method __set()
	 *
	 * @param string $name Name of the parameter being modified.
	 * @param string $value Value to set to the property with name $name.
	 * @param string $realValue Value built by the pseudo-method __set().
	 * @return boolean Returns true when it is alright to modify the property.
	 */
	protected function subSet($name, &$value, &$realValue) {
		//
		// Checking property rules.
		switch($name) {
			case "parent":
				//
				// Collection parent's flow is no longer valid.
				$collection = $this->parentCollection();
				if($collection && $collection->ok()) {
					$collection->setValidFlow(false);
				}
				//
				// Collection new parent's flow is no longer valid.
				if($realValue != 0) {
					$collections = WCCollectionsHolder::I()->item($realValue);
					$collection = array_shift($collections);
					if($collection && $collection->ok()) {
						$collection->setValidFlow(false);
					}
				}
				break;
			case "name":
				//
				// When the property being modified is the class
				// name, any search index on it is no longer
				// valid and it should be updated ASAP.
				$this->indexed = false;
				break;
			case "collection":
				//
				// When the property being modified is the
				// collection, last collector user has to be
				// updated.
				{
					global $wcUser;
					$this->collector = $wcUser->id;
				}
				break;
		}
		//
		// There are no conditions in this method that my interrupt the
		// property change.
		return true;
	}
	protected function updateStats() {
		//
		// Creating a statement request members of this collection.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__."[stats]";
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "update  {$this->_dbprefix}collections\n";
			$query .= "set     col_count = (\n";
			$query .= "                select  count(*)\n";
			$query .= "                from    {$this->_dbprefix}comics\n";
			$query .= "                where   cmc_collection = :collection\n";
			$query .= "                 and    cmc_lost       = 'N'\n";
			$query .= "        ),\n";
			$query .= "        col_icount = (\n";
			$query .= "                select  count(*)\n";
			$query .= "                from    {$this->_dbprefix}images\n";
			$query .= "                where   img_collection = :collection\n";
			$query .= "                 and    img_lost       = 'N'\n";
//			$query .= "        ),\n";
//			$query .= "        col_subcount = (\n";
//			$query .= "                select  count(*)\n";
//			$query .= "                from    {$this->_dbprefix}collections c2\n";
//			$query .= "                where   c2.col_parent = :collection\n";
			$query .= "        )\n";
			$query .= "where   col_id = :collection\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(":collection" => $this->id);
		$stmt->execute($params);

		$this->subcount = count($this->collections());
		$stmt->closeCursor();
		//
		// Collection flow may no longer be valid.
		$this->setValidFlow(false);
	}
	//
	// Public class methods.
	/**
	 * This is a sorting method based on collection's order indicator. When
	 * the indicator has the same value, it uses NameSort().
	 * It can be used on usort and uasort functions.
	 *
	 * @param WCCollection $a Left operand.
	 * @param WCCollection $b Right operand.
	 * @return boolean Returns true when the order indicator of $a is greater
	 * than $b's.
	 */
	public static function Sort($a, $b) {
		$aorder = $a->order;
		$border = $b->order;
		return $aorder != $border ? $aorder > $border : self::NameSort($a, $b);
	}
	/**
	 * This is a sorting method based on collection id and it can be used on
	 * usort and uasort functions.
	 *
	 * @param WCCollection $a Left operand.
	 * @param WCCollection $b Right operand.
	 * @return boolean Returns true when the id of $a is greater than $b's.
	 */
	public static function IdSort($a, $b) {
		return $a->id > $b->id;
	}
	/**
	 * This is a sorting method based on collection names and it can be used
	 * on usort and uasort functions.
	 *
	 * @param WCCollection $a Left operand.
	 * @param WCCollection $b Right operand.
	 * @return boolean Returns true when the name of $a is greater than
	 * $b's.
	 */
	public static function NameSort($a, $b) {
		return $a->name > $b->name;
	}
	/**
	 * This is a sorting method based on collection paths and it can be used
	 * on usort and uasort functions.
	 *
	 * @param WCCollection $a Left operand.
	 * @param WCCollection $b Right operand.
	 * @return boolean Returns true when the path of $a is greater than
	 * $b's.
	 */
	public static function PathSort($a, $b) {
		return $a->path() > $b->path();
	}
}
